import Axios, { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { message } from 'antd';
import { config } from '~/config/config';

message.config({
  maxCount: 1,
});

export class ResponseException extends Error {
  public res: any;
  public constructor(m: string, res: any) {
    super(m);
    this.res = res;
  }
}

export const axios = Axios.create({
  baseURL: config.remoteUrl,
});

// request header
axios.defaults.headers.common['Access-Control-Allow-Origin'] = '*';
axios.defaults.headers.common['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept';
// 设置服务端响应头：不设置响应会被忽略不可用
axios.defaults.headers.common['Access-Control-Allow-Credentials'] = true;
axios.defaults.headers.common['Cache-Control'] = 'no-cache, no-store, must-revalidate';
axios.defaults.headers.common['Content-Encoding'] = 'gzip';
axios.defaults.headers.common.Expires = 0;
axios.defaults.headers.common.Pragma = 'no-cache';
axios.defaults.headers.common['X-Role'] = 'APPLICANT';

// config
axios.defaults.timeout = 30000;
// withCredentials：跨域请求时是否需要凭证：需要Access-Control-Allow-Credentials为true
axios.defaults.withCredentials = true;

/** request interceptor */
axios.interceptors.request.use(
  (c: AxiosRequestConfig) => {
    c.validateStatus = (status: number) => status >= 200 && status < 500;

    return c;
  },
  (error: Error) => Promise.reject(error),
);

// Add a response interceptor
// had to seperate response and error handles because they all call in chain
// https://github.com/axios/axios/blob/v0.18.0/lib/core/Axios.js#L46
axios.interceptors.response.use(
  (response: AxiosResponse) => {
    if (response.data) {
      if (response.data.code === 403) {
        message.error('Authorization failed, now to Login...', 1, () => {
          window.location.href = `/login?forward=${window.location.href}`;
        });

        throw new ResponseException('Authorization error', response.data);
      }

      // common error
      if (response.data.code !== 200) {
        message.error(response.data.msg || 'System error');

        throw new ResponseException('System error', response.data);
      }

      // code === 200
      return response.data;
    }

    throw new Error('Invalid Response');
  },
  (err: Error) => Promise.reject(err),
);

// handle errors
axios.interceptors.response.use(
  (data: any) => data,
  (error: AxiosError) => {
    throw new ResponseException(error.message, error.response?.data ?? null);
  },
);
